package com.koron.car.web.applycar.service.impl;

import com.koron.bean.base.Response;
import com.koron.car.config.Constants;
import com.koron.car.web.applycar.bean.entity.DriverSchedule;
import com.koron.car.web.applycar.bean.query.LastScheduleQuery;
import com.koron.car.web.applycar.bean.vo.CarApplyVO;
import com.koron.car.web.applycar.mapper.CarApplyMapper;
import com.koron.car.web.applycar.mapper.DriverScheduleMapper;
import com.koron.car.web.applycar.service.DriverScheduleService;
import com.koron.car.web.carledger.bean.vo.CarVO;
import com.koron.car.web.carledger.service.CarService;
import com.koron.car.web.common.CommonUtils;
import com.koron.car.web.driver.bean.vo.DriverVO;
import com.koron.car.web.driver.service.DriverService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * (DriverSchedule)表服务实现类
 *
 * @author twcao
 * @since 2022-03-09 10:37:11
 */
@Service
public class DriverScheduleServiceImpl implements DriverScheduleService {

    @Autowired
    private CarService carService;

    @Autowired
    private DriverService driverService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public DriverSchedule queryById(SessionFactory factory, String id) {
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
        return mapper.queryById(id);
    }

    /**
     * 申请id
     *
     * @param factory
     * @param applyId
     * @return
     */
    @Override
    @TaskAnnotation("getByApplyId")
    public DriverSchedule getByApplyId(SessionFactory factory, String applyId) {
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
        return mapper.getByApplyId(applyId);
    }

    /**
     * 查询多条数据
     *
     * @param query 查询条件
     * @return 对象列表
     */
    @Override
    public List<DriverSchedule> queryList(SessionFactory factory, DriverSchedule query) {
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
        return mapper.queryList(query);
    }

    /**
     * 新增数据
     *
     * @param schedule 实例对象
     * @return 实例对象
     */
    @Override
    @TaskAnnotation("insert")
    public DriverSchedule insert(SessionFactory factory, DriverSchedule schedule) {
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
        Assert.notNull(schedule, "调度信息不能为空");
        Assert.hasText(schedule.getApplyId(), "申请id不能为空");
        DriverSchedule scheduled = mapper.getByApplyId(schedule.getApplyId());
        Assert.isNull(scheduled, "调度信息已存在");
        CommonUtils.update(schedule, ThreadLocalContext.get());
        schedule.setId(CodeTools.getCode32());
        //isAvailable(factory, schedule);
        mapper.insert(schedule);
        return schedule;
    }

    /**
     * 修改数据
     *
     * @param schedule 实例对象
     * @return 实例对象
     */
    @Override
    @TaskAnnotation("update")
    public DriverSchedule update(SessionFactory factory, DriverSchedule schedule) {
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
//        if (schedule.getStartMileage() != null && schedule.getLastEndMileage() != null) {
//            Double currDistance = schedule.getStartMileage() - schedule.getLastEndMileage();
//            Assert.isTrue(currDistance >= 0, "本单开始里程不得小于上单结束里程");
//        }
//        if (schedule.getEndMileage() != null && schedule.getStartMileage() != null) {
//            Double currDistance = schedule.getEndMileage() - schedule.getStartMileage();
//            Assert.isTrue(currDistance >= 0, "本单结束里程不得小于本单开始里程");
//        }
        //isAvailable(factory, schedule);
        mapper.update(schedule);
        CommonUtils.update(schedule, ThreadLocalContext.get());
        return this.queryById(factory, schedule.getId());
    }

    @Override
    @TaskAnnotation("getLastSchedule")
    public DriverSchedule getLastSchedule(SessionFactory factory, LastScheduleQuery query) {
        if (StringUtils.isAllEmpty(query.getCarId(), query.getDriverId())) {
            return new DriverSchedule();
        }
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
        if (StringUtils.isNotBlank(query.getCarId())) {
            query.setDriverId(null);
        }
        // 只查已经完成的
//        query.setStates(Arrays.asList(Constants.ApplyState.FINISH));
        DriverSchedule lastSchedule = mapper.getLastSchedule(query);
        if (lastSchedule == null) {
            lastSchedule = new DriverSchedule();
            CarVO carVO = carService.queryById(factory, query.getCarId());
            BeanUtils.copyProperties(carVO, lastSchedule);
            lastSchedule.setId(null);
            lastSchedule.setCarId(carVO.getId());
            lastSchedule.setStartMileage(0.0);
            lastSchedule.setEndMileage(0.0);
            lastSchedule.setLastStartMileage(0.0);
            lastSchedule.setLastEndMileage(0.0);
        }
        // 第一笔行驶记录
        if ((Objects.isNull(lastSchedule.getLastStartMileage()) && Objects.isNull(lastSchedule.getLastEndMileage()))
                ||
                (lastSchedule.getLastStartMileage() == 0.0 && lastSchedule.getLastEndMileage() == 0.0)
        ) {
            lastSchedule.setLastStartMileage(lastSchedule.getStartMileage());
            lastSchedule.setLastEndMileage(lastSchedule.getEndMileage());
        }
        return lastSchedule;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    @TaskAnnotation("deleteById")
    public boolean deleteById(SessionFactory factory, String id) {
        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);
        return mapper.deleteById(id) > 0;
    }

    @Override
    @TaskAnnotation("checkScheduleTime")
    public Response<Map> checkScheduleTime(SessionFactory factory, DriverSchedule schedule) {
        // 获取当前已审批的车辆的所有调度时间
        String licPlateNum = schedule.getLicPlateNum();
        String driverId = schedule.getDriverId();

        DriverScheduleMapper mapper = factory.getMapper(DriverScheduleMapper.class);

        List<DriverSchedule> licScheduleList = mapper.getAllScheduleInfoByLic(licPlateNum);
        List<DriverSchedule> driverScheduleList = mapper.getAllScheduleInfoByDriver(driverId);
        String licTitle = "当前调度时间与当前选择车辆已调度时间存在冲突！";
        String driverTitle = "当前调度时间与当前选择司机已调度时间存在冲突!";
        Map<String, Object> licInfo = checkScheduleTimeInfo(factory, schedule, licScheduleList, licTitle);
        if (!CollectionUtils.isEmpty(licInfo)) {
            return Response.ok(licInfo);
        }
        Map<String, Object> driverInfo = checkScheduleTimeInfo(factory, schedule, driverScheduleList, driverTitle);
        if (!CollectionUtils.isEmpty(driverInfo)) {
            return Response.ok(driverInfo);
        }
        return Response.ok();
    }

    public Map<String, Object> checkScheduleTimeInfo(SessionFactory factory, DriverSchedule schedule, List<DriverSchedule> list, String title) {
        CarApplyMapper carApplyMapper = factory.getMapper(CarApplyMapper.class);
        Map<String, Object> info = new HashMap<>();
        boolean flag = false;
        // 调度开始时间
        Date startTime = schedule.getStartTime();
        // 调度结束时间
        Date endTime = schedule.getEndTime();
        // 当前申请单id
        String applyId = schedule.getApplyId();
        // title
        if (!CollectionUtils.isEmpty(list)) {
            for (DriverSchedule driverSchedule : list) {
                flag = hasOverlap(startTime, endTime, driverSchedule.getStartTime(), driverSchedule.getEndTime());
                // 当前时间冲突
                if (flag && !StringUtils.equals(applyId, driverSchedule.getApplyId())) {
                    CarApplyVO carApplyVO = carApplyMapper.queryById(driverSchedule.getApplyId());
                    info.put("title", title);
                    info.put("code", carApplyVO != null ? carApplyVO.getCode() : null);
                    info.put("chooseStartTime", startTime);
                    info.put("chooseEndTime", endTime);
                    info.put("conflictStartTime", driverSchedule.getStartTime());
                    info.put("conflictEndTime", driverSchedule.getEndTime());
                }
            }
        }
        return info;
    }

    /**
     * 检查调度信息是否可用
     *
     * @param factory
     * @param schedule
     * @return
     */
    private boolean isAvailable(SessionFactory factory, DriverSchedule schedule) {
        Assert.notNull(schedule, "调度信息不能为空");
        String carId = schedule.getCarId();
        if (StringUtils.isNotBlank(carId)) {
            CarVO carVO = carService.queryById(factory, carId);
            Assert.isTrue(StringUtils.equals(carVO.getState(), Constants.CarState.FREE), "不能调用非空闲状态的车辆");
        }
        String driverId = schedule.getDriverId();
        if (StringUtils.isNotBlank(driverId)) {
            DriverVO driverVO = driverService.queryById(factory, driverId);
            Assert.isTrue(StringUtils.equals(driverVO.getWorkState(), Constants.DriverWorkState.FREE), "不能指派非空闲状态的司机");
        }
        return true;
    }

    /**
     * 思路：将有交集的情况列出,若不符合有交集的情况,则无交集
     * 有交集的两种情况
     * 1.第一个时间段的开始时间在第二个时间段的开始时间和结束时间当中
     * 2.第二个时间段的开始时间在第一个时间段的开始时间和结束时间当中
     * 判断两个时间段是否有交集
     *
     * @param leftStartDate  第一个时间段的开始时间
     * @param leftEndDate    第一个时间段的结束时间
     * @param rightStartDate 第二个时间段的开始时间
     * @param rightEndDate   第二个时间段的结束时间
     * @return 若有交集, 返回true, 否则返回false
     */
    public boolean hasOverlap(Date leftStartDate, Date leftEndDate, Date rightStartDate, Date rightEndDate) {

        return ((leftStartDate.getTime() >= rightStartDate.getTime())
                && leftStartDate.getTime() < rightEndDate.getTime())
                ||
                ((leftStartDate.getTime() > rightStartDate.getTime())
                        && leftStartDate.getTime() <= rightEndDate.getTime())
                ||
                ((rightStartDate.getTime() >= leftStartDate.getTime())
                        && rightStartDate.getTime() < leftEndDate.getTime())
                ||
                ((rightStartDate.getTime() > leftStartDate.getTime())
                        && rightStartDate.getTime() <= leftEndDate.getTime());

    }

}
